﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MvcEngine.Core.Exceptions;

namespace MvcEngine.Core.Base
{
    /// <summary>
    /// A class representing a single entity field.
    /// </summary>
    public class EntityField
    {
        private string name;
        private object value;
        private Dictionary<string, string> attributes = new Dictionary<string, string>();

        /// <summary>
        /// Occurs when the field has been changed.
        /// </summary>
        public event EventHandler Changed;

        /// <summary>
        /// Raises the <see cref="Changed"/> event.
        /// </summary>
        protected void OnChanged()
        {
            if (Changed != null)
                Changed(this, EventArgs.Empty);
        }

        /// <summary>
        /// Gets or sets the name of the field.
        /// </summary>
        /// <value>The name of the field.</value>
        public string Name
        {
            get { return this.name; }
            set { this.name = value; OnChanged(); }
        }

        /// <summary>
        /// Gets or sets the field value.
        /// </summary>
        /// <value>The field value.</value>
        public object Value
        {
            get { return this.value; }
            set { this.value = value; OnChanged(); }
        }

        /// <summary>
        /// Gets or sets the value for the specified attribute.
        /// </summary>
        /// <value></value>
        public string this[string attribute]
        {
            get { return Get(attribute); }
            set { Set(attribute, value); }
        }

        /// <summary>
        /// Sets the value for the specified attribute.
        /// </summary>
        /// <param name="attribute">The attribute name.</param>
        /// <param name="value">The attribute value.</param>
        /// <returns></returns>
        public EntityField Set(string attribute, string value)
        {
            ValidateAttribute(attribute);
            attributes[attribute] = value;
            OnChanged();
            return this;
        }

        /// <summary>
        /// Gets the value for the specified attribute.
        /// </summary>
        /// <param name="attribute">The attribute name.</param>
        /// <returns></returns>
        public string Get(string attribute)
        {
            string value;
            if (attributes.TryGetValue(attribute, out value))
                return value;
            else
                return null;
        }

        /// <summary>
        /// Gets the attributes enumerable.
        /// </summary>
        /// <returns></returns>
        public IEnumerable<KeyValuePair<string, string>> GetAttributes()
        {
            return attributes;
        }

        /// <summary>
        /// Creates a clone of this field.
        /// </summary>
        /// <returns></returns>
        public EntityField Clone()
        {
            var clone = new EntityField() { name = this.name, value = this.value };
            foreach (var item in this.attributes)
                clone[item.Key] = item.Value;
            return clone;
        }

        /// <summary>
        /// Validates the attribute name using Regex.
        /// </summary>
        /// <param name="name">The attribute name.</param>
        private void ValidateAttribute(string name)
        {
            bool result = System.Text.RegularExpressions.Regex.IsMatch(name, @"^[A-Za-z][A-Za-z0-9\-]*$",
                System.Text.RegularExpressions.RegexOptions.Compiled);
            if (!result)
                throw new BusinessException("Attribute name has to be in the following format: {letter}{letter|digit|'-'}.");
        }
    }
}
